import DesignResource from "./DesignResource.js";

let Fabric = null;

class Render {
    // 构造函数
    constructor(FabricClass, element, option = {}) {
        // 容器嵌套逻辑，包括画布、映射器、设计区、滤镜、遮罩
        // 最外层容器是画布
        // 设计器映射到映射器上展示

        !Fabric && FabricClass && (Fabric = FabricClass);

        // 画布相关
        this.canvas_scale = option.canvas_scale || 1;
        this.canvas_name = option.canvas_name;
        this.canvas_width = option.canvas_width;
        this.canvas_height = option.canvas_height;
        this.canvas_model = option.canvas_model || "simple"; // [simple|print] 精简模式、打印模式

        // 图层
        this.stage = new Map();
        // 渲染器
        this.cache = {
            string: "",
            status: "inited",
            loop: [], // 渲染队列
        };

        this.onUpdate = option.onUpdate || null;
        this.layers = option.design_layers || [];

        // 纯展示用
        this.fabric = new Fabric.StaticCanvas(element || null, {
            enableRetinaScaling: false,
            width: this.canvas_width * this.canvas_scale,
            height: this.canvas_height * this.canvas_scale,
        });

        // 文字变形方案
        // 存在缩放问题
        // https://stackoverflow.com/questions/19726778/create-valley-text-text-with-curve-in-fabric-js
        // http://jsfiddle.net/NHs8t/
        // http://jsfiddle.net/7vcgoydr/1/
    }

    reset(option) {
        this.canvas_scale = option.canvas_scale || 1;
        this.canvas_name = option.canvas_name;
        this.canvas_width = option.canvas_width;
        this.canvas_height = option.canvas_height;
        this.canvas_model = option.canvas_model || "simple"; // [simple|print] 精简模式、打印模式

        this.onUpdate = option.onUpdate || null;

        this.layers = option.design_layers || [];
        this.fabric.setWidth(this.canvas_width * this.canvas_scale);
        this.fabric.setHeight(this.canvas_height * this.canvas_scale);
    }

    // 更新元素
    updateLayer(layer) {
        // 可能内容不变，可不用更新
        let stage = this.stage.get(layer);

        if (!stage) {
            // 没有数据，不用管
            return Promise.reject("layer must set in stage map");
        } else if (layer.type == "image") {
            // fabric默认添加图片到画布的时候，是使用图片资源的本身真实宽高来绘制的
            let image = stage._element || { width: layer.w, height: layer.h };
            // let imageScale = Math.max(layer.imageW/image.width, layer.imageH/image.height);
            let canvasScale =
                this.canvas_scale /
                Math.max(image.width / layer.w, image.height / layer.h);

            stage.set({
                left:
                    layer.x * this.canvas_scale +
                    0.5 * layer.w * this.canvas_scale,
                top:
                    layer.y * this.canvas_scale +
                    0.5 * layer.h * this.canvas_scale,
                width: image.width,
                height: image.height,
                angle: layer.rotate,
                scaleX: canvasScale,
                scaleY: canvasScale,
                flipX: layer.flipX,
                flipY: layer.flipY,
                originX: "center",
                originY: "center",
            });

            return Promise.resolve();
        } else if (layer.type == "text") {
            let scale = this.canvas_scale;

            let fontFamily = layer.font_family || "Arial";
            let fontSize = layer.font_size * scale;
            let lineHeight = layer.font_size * scale;
            let charSpacing = layer.letter_spacing * 1000;

            let shadow = null;

            if (layer.shadow_distance && layer.shadow_color) {
                // 模糊度
                let blur = layer.shadow_blur * layer.font_size * scale;
                // 偏移距离
                let distance = layer.shadow_distance * layer.font_size * scale;
                // 偏移角度
                let radians =
                    ((layer.shadow_angle + -layer.rotate) % 360) *
                    (Math.PI / 180);

                shadow = new Fabric.Shadow({
                    blur: blur,
                    offsetX: Math.sin(radians) * distance,
                    offsetY: Math.cos(radians) * distance,
                    nonScaling: true,
                    affectStroke: true,
                    color: layer.shadow_color,
                });
            }

            // 外部容器位置
            stage.set({
                left: layer.x * scale + 0.5 * layer.w * scale,
                top: layer.y * scale + 0.5 * layer.h * scale,
                width: layer.w * scale,
                height: layer.h * scale,
                angle: layer.rotate,
                flipX: layer.flipX,
                flipY: layer.flipY,

                text: String(layer.text),
                fill: layer.font_color,
                fontSize: fontSize,
                lineHeight: lineHeight,
                charSpacing: charSpacing,
                paintFirst: "stroke",
                stroke: layer.outline_color,
                strokeWidth: layer.outline_weight * layer.font_size * scale,
                shadow: shadow,
            });

            if (stage.fontFamily == fontFamily) {
                return Promise.resolve();
            } else {
                return new Promise((resolve) => {
                    DesignResource.loadFont(fontFamily)
                        .then((font) => {
                            if (layer.font_family == fontFamily) {
                                stage.set({ fontFamily: fontFamily });
                            }
                            resolve();
                        })
                        .catch((error) => resolve());
                });
            }
        } else {
            return Promise.reject("unknown type" + JSON.stringify(layer));
        }
    }

    // 插入元素
    insertLayer(layer) {
        if (layer.type == "image") {
            // 没有链接，或是没有加载资源，或是资源加载未完成
            // 加载中的效果
            // let url = this.canvas_model == 'simple' ? (layer.thumb || layer.url || '') : layer.url || '';
            let stage = new Fabric.Image(null, {
                originX: "center",
                originY: "center",
            });

            let urlOption = {
                type: this.canvas_model,
                form: "materials",
            };

            let image = DesignResource.getImageByCache(layer.url, urlOption);

            this.fabric.add(stage);
            this.stage.set(layer, stage);

            if (image) {
                stage.setElement(image);
                return this.updateLayer(layer);
            } else {
                let minOption = {
                    type: "fastest",
                    form: "materials",
                };
                stage.set({ backgroundColor: "#f2f2f2" });

                // 没有图片的，先渲染一次
                this.updateLayer(layer).then((e) => {
                    this.fabric.renderAll();
                    this.onUpdate && this.onUpdate(this.fabric);
                });

                // 先加载小图，再加载大图
                return DesignResource.loadImage(layer.url, minOption)
                    .then((img) => {
                        stage.set({ backgroundColor: null });
                        stage.setElement(img);
                        this.updateLayer(layer).then((e) => {
                            this.fabric.renderAll();
                            this.onUpdate && this.onUpdate(this.fabric);
                        });
                        return Promise.resolve();
                    })
                    .then((e) => DesignResource.loadImage(layer.url, urlOption))
                    .then((img) => {
                        stage.setElement(img);
                        return this.updateLayer(layer);
                    });
            }
        } else if (layer.type == "text") {
            let text = new Fabric.Text(layer.text, {
                originX: "center",
                originY: "center",
                textAlign: "center",
                fontFamily: layer.font_family || "Arial",
            });

            this.fabric.add(text);
            this.stage.set(layer, text);
            this.updateLayer(layer);

            if (DesignResource.getFontByCache(layer.font_family)) {
                return this.updateLayer(layer);
            } else {
                return new Promise((resolve) => {
                    DesignResource.loadFont(layer.font_family)
                        .then((font) => {
                            resolve(this.updateLayer(layer));
                        })
                        .catch((error) => {
                            resolve(this.updateLayer(layer));
                        });
                });
            }
        } else {
            return Promise.reject("unknown type" + JSON.stringify(layer));
        }
    }

    // 删除元素
    removeLayer(layer) {
        let stage = this.stage.get(layer);
        if (stage) {
            this.stage.delete(layer);
            this.fabric.remove(stage);
            return Promise.resolve();
        } else {
            return Promise.reject();
        }
    }

    // 渲染图层，事务处理，按顺序执行
    renderLayers(option) {
        let layers = option && option.map ? option : this.layers;
        let string = JSON.stringify({
            canvas_scale: this.canvas_scale,
            canvas_width: this.canvas_width,
            canvas_height: this.canvas_height,
            canvas_model: this.canvas_model,
            layers: layers,
        });

        if (!this.fabric) {
            // 没有canvas
            return Promise.reject("fabric Uninitialized");
        } else if (
            this.cache.string == string &&
            this.cache.status == "complete"
        ) {
            // 相同
            return Promise.resolve(this.fabric);
        } else if (
            this.cache.string == string &&
            this.cache.status == "loading"
        ) {
            // 加载中
            return new Promise((resolve, reject) => {
                this.cache.loop.push((fabric) => {
                    if (fabric) {
                        resolve(fabric);
                    } else {
                        reject();
                    }
                });
            });
        } else {
            return new Promise((resolve, reject) => {
                let promises = [];

                // 新增或修改
                layers.map((layer, index) => {
                    if (this.stage.get(layer)) {
                        promises.push(this.updateLayer(layer));
                    } else {
                        // 添加
                        promises.push(this.insertLayer(layer));
                    }
                });

                // 删除
                this.stage.forEach((stage, layer) => {
                    if (layers.indexOf(layer) >= 0) {
                        // 存在的，不用删除
                    } else {
                        promises.push(this.removeLayer(layer));
                    }
                });

                this.layers = layers;
                this.cache.status = "loading";
                this.cache.string = string;

                Promise.all(promises)
                    .then((e) => {
                        // 图层排序
                        layers.map((item, index) =>
                            this.fabric.moveTo(this.stage.get(item), index)
                        );
                        // 渲染
                        this.fabric.renderAll();

                        resolve(this.fabric);

                        this.onUpdate && this.onUpdate(this.fabric);
                        this.cache.status = "complete";
                        this.cache.loop.map((cb) => cb(this.fabric));
                        this.cache.loop = [];
                    })
                    .catch((error) => {
                        reject(this.fabric);
                        this.cache.status = "error";
                        this.cache.loop.map((cb) => cb());
                        this.cache.loop = [];
                    });
            });
        }
    }

    // 销毁
    destroy() {
        // this.pixi.destroy();
    }

    // 创建
    // 销毁
    // 更新设计区
    // 更新尺寸
}

export default Render;
